package dryven.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;


public class ImageScaler {
	
	private String _filename;
	
	public ImageScaler(String filename) {
		_filename = filename;
	}
	
	private Image loadImage() throws IOException {
		InputStream is = new FileInputStream(_filename);
		Image img = ImageIO.read(is);
		return img;
	}
	
	private void writeImage(BufferedImage buf, String name) throws IOException {
		FileOutputStream fos = new FileOutputStream(name);
		ImageIO.write(buf, "PNG", fos);
		fos.flush();
		fos.close();
	}
	
	public void scaleProportional(int maxWidth, int maxHeight, String newFilename) throws IOException {
		Image img = loadImage();
		
		Point srcSize = new Point(img);
		Point dstMaxSize = new Point(maxWidth, maxHeight);
		Point dstSize;
		//limited by width
		if(srcSize.ratio()>dstMaxSize.ratio()) {
			dstSize = new Point(maxWidth,(int)(((double)maxWidth)*(1.0/srcSize.ratio())));
		}
		//limited by height
		else {
			double factor = ((double)maxHeight)/((double)srcSize.height());
			dstSize = new Point((int)(((double)srcSize.width())*factor),maxHeight);
		}
		
		BufferedImage buf = new BufferedImage(dstSize.width(), dstSize.height(), BufferedImage.TYPE_INT_RGB);
		Graphics2D g = createGraphics(buf);
		
		//Point dstOrigin = new Point((dstMaxSize.width()/2)-(dstSize.width()/2), (dstMaxSize.height()/2)-(dstSize.height()/2));
		g.drawImage(img, 0, 0, dstSize.width(), dstSize.height(), 0, 0, srcSize.width(), srcSize.height(), null);
		g.dispose();
		writeImage(buf, newFilename);
	}
	
	public void scaleCropped(int width, int height, String newFilename) throws IOException {
		BufferedImage buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Image img = loadImage();
		Graphics2D g = createGraphics(buf);
		
		Point srcSize = new Point(img);
		Point dstSize = new Point(width,height);
		Point cutSize;
		//limited by height
		if(srcSize.ratio()>dstSize.ratio()) {
			cutSize = new Point((int)(((double)srcSize.height())*dstSize.ratio()),srcSize.height());
		}
		//limited by width
		else {
			cutSize = new Point(srcSize.width(),(int)(((double)srcSize.width())/dstSize.ratio()));
		}
		Point cutOrigin = new Point((srcSize.width()/2)-(cutSize.width()/2), (srcSize.height()/2)-(cutSize.height()/2));
		g.drawImage(img, 0, 0, width, height, cutOrigin.x(), cutOrigin.y(), cutOrigin.x()+cutSize.width(), cutOrigin.y()+cutSize.height(), null);
		g.dispose();
		writeImage(buf, newFilename);
	}

	protected Graphics2D createGraphics(BufferedImage buf) {
		Graphics2D g = buf.createGraphics();
		g.setBackground(Color.WHITE);
		g.setPaint(Color.WHITE);
		g.fillRect(0, 0, buf.getWidth(), buf.getHeight());
	    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
		return g;
	}
}

class Point {
	
	private int x, y;
	
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	public Point(Image img) {
		this.x = img.getWidth(null);
		this.y = img.getHeight(null);
	}
	
	public double ratio() {
		return ((double)x)/((double)y);
	}
	
	public int x() {
		return x;
	}
	
	public int y() {
		return y;
	}
	
	public int width() {
		return x;
	}
	
	public int height() {
		return y;
	}
	
	public String toString() {
		return x+"x"+y+" ratio("+ratio()+")";
	}
}
